<script lang="ts" setup>
import dataRaw from './data.json'
import { pinyin } from 'pinyin-pro'
import { useConfigStore } from './stores/config'
useDark()
const data = dataRaw.filter((e) => [...e].length === 4)
const input = ref('')
const info = ref('')
const output: Ref<string[]> = ref([])
const isShowRobotTalkFirst = ref(true)
const count = ref(0)
const { maxCount } = storeToRefs(useConfigStore())
const inputList: string[] = reactive([])
const ouputList: string[] = reactive([])

watch(input, (v) => {
  info.value = ''
  if (!v.length) return
  if (!data.find((e) => e === v)) {
    info.value = '必须是成语'
    return
  }
  if (
    output.value.length &&
    !output.value.find(
      (e) =>
        e.endsWith([...v][0]) ||
        pinyin(e, { toneType: 'none', type: 'array' }).at(-1) ===
          pinyin(v, { toneType: 'none', type: 'array' })[0]
    )
  )
    info.value = '错了'
  if (inputList.includes(input.value)) {
    info.value = '重复了'
    return
  }
})
function getRandomInt(min: number, max: number) {
  min = Math.ceil(min)
  max = Math.floor(max)
  return Math.floor(Math.random() * (max - min)) + min //不含最大值，含最小值
}
const worker = new Worker(new URL('./worker/worker.ts', import.meta.url), {
  type: 'module'
})
const inputBox: Ref<HTMLInputElement | null> = ref(null)
async function submit() {
  inputBox.value?.focus()
  info.value = ''
  if (!data.find((e) => e === input.value)) {
    info.value = '必须是成语'
    return
  }
  if (
    output.value.length &&
    !output.value.find(
      (e) =>
        e.endsWith([...input.value][0]) ||
        pinyin(e, { toneType: 'none', type: 'array' }).at(-1) ===
          pinyin(input.value, { toneType: 'none', type: 'array' })[0]
    )
  ) {
    info.value = '错了'
    return
  }
  if (inputList.includes(input.value)) {
    info.value = '重复了'
    return
  }
  let t = await new Promise<string[]>((resolve, reject) => {
    worker.postMessage({
      data,
      input: input.value,
      inputList: toRaw(inputList),
      ouputList: toRaw(ouputList)
    })
    worker.addEventListener('message', ({ data }) => {
      resolve(data)
    })
    worker.addEventListener('error', (e) => reject(e))
    worker.addEventListener('messageerror', (e) => reject(e))
  })
  inputBox.value?.select()
  if (!t.length) {
    info.value = '你赢了'
    isShowRobotTalkFirst.value = true
    inputList.length = 0
    ouputList.length = 0
    return
  }
  inputList.push(input.value)
  ouputList.push(...(output.value = [t[getRandomInt(0, t.length)]]))
  isShowRobotTalkFirst.value = false
  count.value++
}
watch(count, (v) => {
  if (v > maxCount.value) {
    maxCount.value = v
  }
})
</script>

<template>
  <div class="grid min-h-full place-content-center">
    <section
      class="max-w-md rounded-md border border-opacity-5 bg-white p-6 shadow-lg dark:border-none dark:bg-transparent"
    >
      <h2 class="text-2xl font-semibold capitalize text-gray-700 dark:text-gray-300">成语接龙</h2>
      <div class="mt-2">
        最高记录：<span>{{ maxCount }}</span>
      </div>
      <div>
        当前回合数：<span>{{ count }}</span>
      </div>
      <form @submit.prevent="submit">
        <div class="mt-4 grid grid-cols-1 gap-6">
          <div>
            <label class="text-gray-700 dark:text-gray-300">
              输入
              <input
                type="text"
                placeholder="输入成语"
                v-model.trim="input"
                ref="inputBox"
                size="40"
                autofocus
                class="mt-2 block w-full rounded-md border border-gray-300 bg-transparent px-4 py-2 text-gray-700 outline-none transition focus:border-blue-400 focus:ring focus:ring-blue-300 focus:ring-opacity-40 dark:border-gray-600 dark:text-gray-300 dark:focus:border-blue-300"
              />
            </label>
            <div class="ml-2 mt-2">{{ info }}</div>
          </div>
        </div>
        <div class="mt-6 flex justify-end gap-4">
          <button
            type="button"
            :class="{
              'opacity-0': !isShowRobotTalkFirst,
              'pointer-events-none': !isShowRobotTalkFirst
            }"
            @click="
              () => {
                output = [data[getRandomInt(0, data.length)]] ?? []
                isShowRobotTalkFirst = false
                inputBox?.focus()
              }
            "
            class="transform rounded-md bg-gray-700 px-8 py-2.5 leading-5 text-white transition duration-300 hover:bg-gray-600 focus:bg-gray-600 focus:outline-none dark:bg-opacity-40 dark:text-gray-200"
          >
            机器人先说
          </button>
          <button
            type="submit"
            class="transform rounded-md bg-gray-700 px-8 py-2.5 leading-5 text-white transition-colors duration-300 hover:bg-gray-600 focus:bg-gray-600 focus:outline-none dark:bg-opacity-40 dark:text-gray-200"
          >
            提交
          </button>
        </div>
        <Transition name="spread">
          <output
            v-if="output.length"
            class="mt-6 block text-center text-xl text-gray-700 dark:text-gray-300"
          >
            <TransitionGroup
              type="animation"
              name="bounce"
              tag="ul"
              class="relative overflow-hidden"
            >
              <li v-for="item in output" :key="item" class="select-text transition">
                {{ item }}
              </li>
            </TransitionGroup>
          </output>
        </Transition>
      </form>
    </section>
  </div>
</template>

<style scoped lang="postcss">
.list-move, /* 对移动中的元素应用的过渡 */
.list-enter-active,
.list-leave-active {
  @apply transition-all duration-500;
}
.list-enter-from,
.list-leave-to {
  @apply translate-x-8;
}
.list-leave-active {
  @apply absolute;
}

.bounce-enter-active {
  animation: bounce-in 0.8s ease-in-out;
}
.bounce-leave-active {
  animation: bounce-out 0.8s ease-in-out;
}
@keyframes bounce-in {
  0% {
    transform: translateX(50%);
    opacity: 0;
  }
}
@keyframes bounce-out {
  0% {
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
  }
  100% {
    width: 100%;
    position: absolute;
    right: 0;
    top: 0;
    transform: translateX(-50%);
    opacity: 0;
  }
}

.spread-enter-active,
.spread-leave-active {
  @apply overflow-hidden transition-all duration-500;
}
.spread-enter-from,
.spread-leave-to {
  @apply my-0 h-0 border-y-0 py-0 opacity-0 outline-0;
}

.opacity-enter-active,
.opacity-leave-active {
  @apply transition-all duration-500;
}
.opacity-enter-from,
.opacity-leave-to {
  @apply opacity-0;
}
</style>
